﻿Imports SlimDX
Imports SlimDX.Direct3D9

Public Class ShaderModel
    Implements IShader

    Dim Base As Texture
    Dim Multi As Texture
    Dim Detail As Texture
    Dim Cube As CubeTexture

    Dim DetailMask As Short
    Dim DetailFunction As Integer
    Dim DetailAfterReflection As Boolean

    Dim DetailScale, DetailVScale, uScale, vScale As Single
    Dim parallelBrightness, perpendicularBrightness As Single

    Dim sILower, sIUpper As Single()
    Dim AnimationFunction As Short
    Dim AnimationPeriod As Single
    Dim flags As Short

    Sub New(ByVal sosoTag As Magic.Core.Tag)
        AddHandler sosoTag.TagHasChanged, AddressOf Changed
        Dim BaseIndex As Integer = sosoTag("base map")
        Dim MultiIndex As Integer = sosoTag("multipurpose map")
        Dim DetailIndex As Integer = sosoTag("detail map")
        Dim CubeIndex As Integer = sosoTag("reflection cube map")

        DetailMask = sosoTag("detail mask")
        DetailAfterReflection = CBool((sosoTag(12) And 1) <> 0)
        DetailFunction = CInt(sosoTag("detail function"))
        DetailScale = CSng(sosoTag("detail map scale"))
        DetailVScale = CSng(sosoTag("detail v-scale"))

        uScale = CSng(sosoTag("map u-scale"))
        vScale = CSng(sosoTag("map v-scale"))

        parallelBrightness = CSng(sosoTag("parallel brightness:[0,1]"))
        perpendicularBrightness = CSng(sosoTag("perpendicular brightness:[0,1]"))


        sILower = sosoTag("animation color lower bound")
        sIUpper = sosoTag("animation color upper bound")


        AnimationFunction = sosoTag("animation function")
        AnimationPeriod = sosoTag("animation period:seconds")

        flags = sosoTag(12)

        If BaseIndex > -1 Then
            Base = New Bitmap(magicMap.Library(BaseIndex)).Texture
        Else
            Base = Globals.default2d(IShader.DefaultTextures.Additive)
        End If
        If MultiIndex > -1 Then
            Multi = New Bitmap(magicMap.Library(MultiIndex)).Texture
        Else
            Multi = Globals.default2d(IShader.DefaultTextures.Additive)
        End If
        If DetailIndex > -1 Then
            Detail = New Bitmap(magicMap.Library(DetailIndex)).Texture
        Else
            Detail = Globals.default2d(IShader.DefaultTextures.SignedAdditive)
        End If
        If CubeIndex > -1 Then
            Cube = New Bitmap(magicMap.Library(CubeIndex)).Cube
        Else
            Cube = Globals.defaultCube(IShader.DefaultTextures.SignedAdditive)
        End If
    End Sub
    Sub Changed(ByVal sosoTag As Magic.Core.Tag)
        Dim BaseIndex As Integer = sosoTag("base map")
        Dim MultiIndex As Integer = sosoTag("multipurpose map")
        Dim DetailIndex As Integer = sosoTag("detail map")
        Dim CubeIndex As Integer = sosoTag("reflection cube map")

        DetailMask = sosoTag("detail mask")
        DetailAfterReflection = CBool((sosoTag(12) And 1) <> 0)
        DetailFunction = CInt(sosoTag("detail function"))
        DetailScale = CSng(sosoTag("detail map scale"))
        DetailVScale = CSng(sosoTag("detail v-scale"))

        uScale = CSng(sosoTag("map u-scale"))
        vScale = CSng(sosoTag("map v-scale"))

        parallelBrightness = CSng(sosoTag("parallel brightness:[0,1]"))
        perpendicularBrightness = CSng(sosoTag("perpendicular brightness:[0,1]"))


        sILower = sosoTag("animation color lower bound")
        sIUpper = sosoTag("animation color upper bound")


        AnimationFunction = sosoTag("animation function")
        AnimationPeriod = sosoTag("animation period:seconds")

        flags = sosoTag(12)

        If BaseIndex > -1 Then
            Base = New Bitmap(magicMap.Library(BaseIndex)).Texture
        Else
            Base = Globals.default2d(IShader.DefaultTextures.Additive)
        End If
        If MultiIndex > -1 Then
            Multi = New Bitmap(magicMap.Library(MultiIndex)).Texture
        Else
            Multi = Globals.default2d(IShader.DefaultTextures.Additive)
        End If
        If DetailIndex > -1 Then
            Detail = New Bitmap(magicMap.Library(DetailIndex)).Texture
        Else
            Detail = Globals.default2d(IShader.DefaultTextures.SignedAdditive)
        End If
        If CubeIndex > -1 Then
            Cube = New Bitmap(magicMap.Library(CubeIndex)).Cube
        Else
            Cube = Globals.defaultCube(IShader.DefaultTextures.SignedAdditive)
        End If
    End Sub
    Public Overloads Sub BeginPass(ByVal pass As Integer) Implements IShader.BeginPass
        If (pass = 0) Then
            xDevice.SetRenderState(RenderState.AlphaBlendEnable, False)
            If ((flags And 4) <> 0) Then
                xDevice.SetRenderState(RenderState.AlphaTestEnable, False)
                xDevice.SetRenderState(RenderState.SourceBlend, Blend.DestinationColor)
                xDevice.SetRenderState(RenderState.DestinationBlend, Blend.Zero)
            Else
                xDevice.SetRenderState(RenderState.AlphaTestEnable, True)
                xDevice.SetRenderState(RenderState.AlphaRef, 127)
                xDevice.SetRenderState(RenderState.AlphaFunc, Compare.GreaterEqual)
                xDevice.SetRenderState(RenderState.SourceBlend, Blend.SourceAlpha)
                xDevice.SetRenderState(RenderState.DestinationBlend, Blend.InverseSourceAlpha)
            End If
            xDevice.SetRenderState(RenderState.CullMode, IIf((flags And 2 = 0), Cull.Counterclockwise, Cull.None))
        End If
        sosoEffect.BeginPass(pass)
    End Sub
    Public Overloads Sub EndPass() Implements IShader.EndPass
        sosoEffect.EndPass()
    End Sub
    Overloads Sub Dispose()
        If Not Base.Disposed Then Base.Dispose()
        If Not Detail.Disposed Then Detail.Dispose()
    End Sub
    Public Overloads Function BeginShader(ByVal tLightmap As Texture) As Integer Implements IShader.BeginShader
        sosoEffect.SetValue("cameraPosition", New Vector4(Camera.Position.X, Camera.Position.Y, Camera.Position.Z, 1.0F))
        sosoEffect.SetValue("world", xDevice.GetTransform(TransformState.World))
        sosoEffect.SetValue("worldViewProjection", xDevice.GetTransform(TransformState.World) * xDevice.GetTransform(TransformState.View) * xDevice.GetTransform(TransformState.Projection))
        sosoEffect.SetValue("selfIlluminationValue", Animate(AnimationFunction, AnimationPeriod, 0.0F))
        sosoEffect.SetValue("fogStart", xDevice.GetRenderState(RenderState.FogStart)) '0.0F) ' MdxRender.Device.RenderState.FogStart);
        sosoEffect.SetValue("fogEnd", xDevice.GetRenderState(RenderState.FogEnd)) ' MdxRender.Device.RenderState.FogEnd);
        sosoEffect.SetValue("fogDensity", xDevice.GetRenderState(RenderState.FogDensity)) ' MdxRender.Device.RenderState.FogDensity);
        sosoEffect.SetValue("ambientColor", New Color4(Color.White))

        sosoEffect.SetValue("changeColor", New Color4(1.0F, 1.0F, 1.0F, 1.0F))

        sosoEffect.SetValue("detailScale", DetailScale)
        sosoEffect.SetValue("detailVScale", DetailVScale)
        sosoEffect.SetValue("uScale", uScale)
        sosoEffect.SetValue("vScale", vScale)

        sosoEffect.SetValue("detailAfterReflection", DetailAfterReflection)
        sosoEffect.SetValue("detailFunction", DetailFunction)

        sosoEffect.SetValue("parallelBrightness", parallelBrightness)
        sosoEffect.SetValue("perpendicularBrightness", perpendicularBrightness)

        sosoEffect.SetValue("selfIlluminationLower", New Color4(1, sILower(0), sILower(1), sILower(2)))
        sosoEffect.SetValue("selfIlluminationUpper", New Color4(1, sIUpper(0), sIUpper(1), sIUpper(2)))

        sosoEffect.SetTexture("BaseMap", Base)
        sosoEffect.SetTexture("EnvironmentMap", Cube)
        sosoEffect.SetTexture("DetailMap", Detail)
        sosoEffect.SetTexture("MultipurposeMap", Multi)

        Select Case DetailMask
            Case 0
                sosoEffect.Technique = "ModelNoDetailMask"
            Case 1
                sosoEffect.Technique = "ModelIReflectionDetailMask"
            Case 2
                sosoEffect.Technique = "ModelReflectionDetailMask"
            Case 3
                sosoEffect.Technique = "ModelIIllumDetailMask"
            Case 4
                sosoEffect.Technique = "ModelIllumDetailMask"
            Case 5
                sosoEffect.Technique = "ModelIChangeColorDetailMask"
            Case 6
                sosoEffect.Technique = "ModelChangeColorDetailMask"
            Case 7
                sosoEffect.Technique = "ModelIAuxiliaryDetailMask"
            Case 8
                sosoEffect.Technique = "ModelAuxiliaryDetailMask"
        End Select

        Return sosoEffect.Begin(FX.DoNotSaveState)
    End Function
    Public Overloads Sub EndShader() Implements IShader.EndShader
        sosoEffect.End()
        xDevice.SetRenderState(RenderState.AlphaTestEnable, False)
        xDevice.SetRenderState(RenderState.SourceBlend, Blend.DestinationColor)
        xDevice.SetRenderState(RenderState.DestinationBlend, Blend.Zero)
    End Sub
End Class
